﻿using System.Collections;
using Basic.FormCollect;
using Basic.FormModel.FormViewCol;
using Basic.FormModel.PageLayout;
using Basic.FormRemoteModel;
using Basic.FormRemoteModel.PageLayout.CensusTable;
using Basic.FormRemoteModel.PageLayout.Chart;
using Basic.FormRemoteModel.PageLayout.Model;
using Basic.UserFormService.Interface;
using Basic.UserFormService.Model;
using SqlSugar;
using WeDonekRpc.CacheClient.Interface;
using WeDonekRpc.Helper;
using WeDonekRpc.SqlSugar.VirtualQuery;

namespace Basic.UserFormService.PageControl
{
    internal class CensusTableBodyCache
    {
        public CensusTableBody Result { get; set; }
        /// <summary>
        /// 筛选条件
        /// </summary>
        public PageFilterParam[] Where { get; set; }

        public HavingColumn Having { get; set; }
    }
    internal class PageCensusTableService : IPageCensusTableService
    {
        private readonly ICustomPageLayoutCollect _Layout;
        private readonly IFormViewColCollect _ViewCol;
        private readonly ICustomFormCollect _Form;
        private readonly ILocalCacheController _Cache;

        public PageCensusTableService ( ICustomPageLayoutCollect layout,
            IFormViewColCollect viewCol,
            ICustomFormCollect form,
            ILocalCacheController cache )
        {
            this._Layout = layout;
            this._ViewCol = viewCol;
            this._Form = form;
            this._Cache = cache;
        }

        public CensusTableBody Get ( long controlId, long companyId, Dictionary<string, string> extend )
        {
            string key = "CensusTableBody_" + controlId;
            if ( !this._Cache.TryGet(key, out CensusTableBodyCache body) )
            {
                body = this._Get(controlId);
                _ = this._Cache.Add(key, body, new TimeSpan(23, 0, 0));
            }
            if ( body.Result.Query == null )
            {
                return body.Result;
            }
            CensusTableBody res = body.Result.Clone();
            res.Query.Having = this._Having(body.Having, body.Result, extend);
            res.Query.Where = body.Where.GetWhere(body.Result.Cols, companyId, extend);
            return res;
        }
        private CensusTableControl _Control;

        private CensusTableCol[] _Cols;

        private Dictionary<long, FormViewColBaseDto> _Columns;
        private PageRowTrunCol _RowTrunCol;
        private CensusTableBodyCache _Get ( long controlId )
        {
            PageLayoutDto layout = this._Layout.Get<PageLayoutDto>(controlId);
            if ( layout.ControlType != PageControlType.统计表 )
            {
                throw new ErrorException("form.page.control.type.error");
            }
            this._Control = layout.ControlConfig.CensusTable;
            QueryStruct query = this._GetQuery();
            return new CensusTableBodyCache
            {
                Having = this._Control.Having,
                Where = this._Control.Where,
                Result = new CensusTableBody
                {
                    FormId = this._Control.FormId,
                    Id = controlId,
                    PageId = layout.PageId,
                    Query = query,
                    Columns = this._GetColumns(),
                    RowTrunCol = this._RowTrunCol,
                    CensusCol = this._GetCensusCol(),
                    MergeCol = this._Cols.Convert(c => c.IsMerge.HasValue && c.IsMerge.Value, c => c.Alias),
                    Cols = this._Columns.ToDictionary(c => c.Key, c =>
                    {
                        return new ColTable
                        {
                            DataType = c.Value.DataType,
                            Name = c.Value.Alias,
                            Table = new WhereTable
                            {
                                Table = query.Table.Name
                            }
                        };
                    })
                }
            };
        }

        private PageColTemplate[] _GetColumns ()
        {
            if ( this._RowTrunCol == null )
            {
                return this._GetColumns(this._Control.Selects);
            }
            return this._RowTrunCol.GroupBy.ConvertAll(c =>
            {
                CensusTableCol col = this._Cols.Find(a => a.Alias == c);
                return new PageColTemplate
                {
                    Align = col.Align,
                    IsRowTrun = false,
                    Label = col.Label,
                    MinWidth = col.MinWidth,
                    Name = c,
                };
            }).Add(new PageColTemplate
            {
                Label = this._RowTrunCol.Label,
                Name = this._RowTrunCol.Name,
                IsRowTrun = true,
                Children = this._Cols.Convert(a => a.Alias != this._RowTrunCol.Name && this._RowTrunCol.GroupBy.Contains(a.Alias) == false, a => new PageColTemplate
                {
                    Align = a.Align,
                    Label = a.Label,
                    MinWidth = a.MinWidth,
                    Name = a.Alias,
                    IsRowTrun = false
                })
            });
        }
        private PageColTemplate[] _GetColumns ( CensusTableCol[] cols )
        {
            return cols.ConvertAll(a =>
            {
                PageColTemplate t = new PageColTemplate
                {
                    Label = a.Label,
                    Align = a.Align,
                    MinWidth = a.MinWidth,
                    Name = a.Alias,
                };
                if ( a.IsGroup )
                {
                    t.Children = a.Children.ConvertAll(a => new PageColTemplate
                    {
                        Align = a.Align,
                        Label = a.Label,
                        MinWidth = a.MinWidth,
                        Name = a.Alias
                    });
                }
                return t;
            });
        }

        private PageRowTrunCol _GetRowTrunCol ()
        {
            CensusTableCol t = this._Cols.Find(a => a.RowTrunCol.HasValue && a.RowTrunCol.Value);
            if ( t == null )
            {
                return null;
            }
            FormViewColBaseDto col = this._Columns[t.ColumnId.Value];
            PageRowTrunCol trun = new PageRowTrunCol
            {
                Label = t.Label,
                Name = t.Alias,
                FuncType = col.ColFuncType,
                DicId = col.DictId,
                GroupBy = t.GroupBy
            };
            if ( col.ColFuncType == FormColumnFuncType.选项值 && col.ColumnSet.TryGetValue("Items", out object val) )
            {
                IList itemList = (IList)val;
                trun.Items = new Dictionary<string, string>();
                foreach ( IDictionary<string, object> k in itemList )
                {
                    object v = k["value"];
                    trun.Items.Add(v == null ? null : Convert.ToString(v), Convert.ToString(k["text"]));
                }
            }
            return trun;
        }
        private PageCensusColumn[] _GetCensusCol ()
        {
            if ( this._Cols.IsNull() )
            {
                return null;
            }
            return this._Cols.Convert(c =>
            {
                if ( c.RowTrunCol.HasValue && c.RowTrunCol.Value )
                {
                    return null;
                }
                else if ( c.FuncType.HasValue && c.FuncType.Value != PageFuncType.None )
                {
                    return null;
                }
                FormViewColBaseDto col = this._Columns[c.ColumnId.Value];
                PageCensusColumn t = new PageCensusColumn
                {
                    Id = col.Id,
                    Name = c.Alias,
                    FuncType = col.ColFuncType,
                    DataType = col.DataType,
                    ColSet = col.ColumnSet
                };
                if ( col.ColFuncType == FormColumnFuncType.选项值 && col.ColumnSet.TryGetValue("Items", out object val) )
                {
                    IList itemList = (IList)val;
                    t.Items = new Dictionary<string, string>();
                    foreach ( IDictionary<string, object> k in itemList )
                    {
                        object v = k["value"];
                        t.Items.Add(v == null ? null : Convert.ToString(v), Convert.ToString(k["text"]));
                    }
                }
                else if ( col.ColFuncType == FormColumnFuncType.字典项 || col.ColFuncType == FormColumnFuncType.树形字典 )
                {
                    t.DicId = col.DictId;
                }
                return t;
            });
        }
        private QueryStruct _GetQuery ()
        {
            string table = this._Form.Get(this._Control.FormId, a => a.TableName);
            this._Columns = this._ViewCol.GetsByFormId<FormViewColBaseDto>(this._Control.FormId).ToDictionary(a => a.Id, a => a);
            List<CensusTableCol> cols = new List<CensusTableCol>();
            this._InitSelect(this._Control.Selects, cols);
            this._Cols = cols.ToArray();
            this._RowTrunCol = this._GetRowTrunCol();
            return new QueryStruct
            {
                Table = new TableStruct
                {
                    Name = table
                },
                GroupBy = this._GroupBy(table),
                OrderBy = this._GetOrderBy(),
                Select = this._GetSelect(table)
            };
        }
        private OrderByStruct[] _GetOrderBy ()
        {
            if ( this._Control.OrderBy == null || this._Control.OrderBy.Count == 0 )
            {
                return null;
            }
            return this._Control.OrderBy.ConvertAll(c =>
            {
                return new OrderByStruct
                {
                    Name = c.Key,
                    IsDesc = c.Value
                };
            });
        }
        private HavingCol? _Having ( HavingColumn having, CensusTableBody body, Dictionary<string, string> extend )
        {
            if ( having == null )
            {
                return null;
            }
            ColTable col = body.Cols[having.ColId];
            return new HavingCol
            {
                DbType = col.DataType.GetDbType(),
                ConditionalType = having.Mode.GetConditionalType(),
                Name = col.Name,
                Table = col.Table.Table,
                Value = having.Value.GetFilterValue(extend),
                Func = having.FuncType.GetQueryFuncType(out string format, out DateType? dateType),
                DateType = dateType,
                Format = format
            };
        }
        private GroupByStruct[] _GroupBy ( string table )
        {
            if ( this._Control.GroupBy.IsNull() )
            {
                return null;
            }
            return this._Control.GroupBy.ConvertAllToArray(c =>
            {
                CensusTableCol col = this._Cols.Find(a => a.Alias == c);
                return new GroupByStruct
                {
                    Name = col.Alias,
                    Table = table,
                    Func = col.FuncType.Value.GetQueryFuncType(out string format, out DateType? dateType),
                    Format = format,
                    DateType = dateType
                };
            });
        }
        private SelectStruct[] _GetSelect ( string table )
        {
            if ( this._Cols.IsNull() )
            {
                return null;
            }
            return this._Cols.ConvertAll(c =>
             {
                 FormViewColBaseDto col = this._Columns[c.ColumnId.Value];
                 return new SelectStruct
                 {
                     Name = col.Alias,
                     Func = c.FuncType.Value.GetQueryFuncType(out string format, out DateType? dateType),
                     DateType = dateType,
                     Format = format,
                     Table = table,
                     Alias = c.Alias
                 };
             });
        }

        private void _InitSelect ( CensusTableCol[] cols, List<CensusTableCol> colList )
        {
            if ( cols.IsNull() )
            {
                return;
            }
            cols.ForEach(c =>
            {
                if ( c.IsGroup )
                {
                    this._InitSelect(c.Children, colList);
                }
                else
                {
                    colList.Add(c);
                }
            });
        }

    }
}